from django.db import models
from django.contrib.auth.models import AbstractUser
from itsdangerous import TimedJSONWebSignatureSerializer as TJWSSerializer, BadData
from django.conf import settings

from meiduo_mall.utils.models import BaseModel
from . import constants


class User(AbstractUser):
    # 追加mobile字段
    mobile = models.CharField(max_length=11, unique=True, verbose_name="手机号")
    # 追加email_active字段,默认邮件未激活
    email_active = models.BooleanField(default=False, verbose_name="邮箱验证状态")
    default_address = models.ForeignKey("Address", related_name="users", null=True, blank=True,
                                        on_delete=models.SET_NULL, verbose_name='默认地址')

    class Meta:
        db_table = "tb_users"
        verbose_name = "用户"
        verbose_name_plural = verbose_name

    def generate_verify_email_url(self):
        """
        生成验证邮箱的url
        """
        serializer = TJWSSerializer(settings.SECRET_KEY, expires_in=constants.VERIFY_EMAIL_TOKEN_EXPIRES)
        data = {
            "user_id": self.id,
            "email": self.email
        }
        token = serializer.dumps(data).decode()
        verify_url = 'http://www.meiduo.site:8080/success_verify_email.html?token=' + token
        return verify_url

    """
    生成邮箱激活码(url)问题分析:
    1.前端进入用户详情页面,输入邮箱点击保存,前端代码vue发送post请求,将验证后的邮箱传到后端视图,视图继承UpdateAPIView;
    2.后端视图拿到数据后验证用户身份信息:permission_classes = [IsAuthenticated],如果用户已登录,则验证通过,并重写get_object方法;
    3.通过后指定序列化器,进行数据验证,因前端已验证过,所以直接保存;
    4.在返回保存数据之前,生成验证邮件:调用itsdangerous方法,将user_id和email(用户点击保存的那一个)打包后的数据加密,添加到验证邮件的地址中;
      (补充:当用户收到验证邮件后,点击网址进行验证,前端将token发送到后端,token)
    5.调用django的send_mail发送邮件;
    6.发送完毕后返回保存后的数据给前端.
    """

    @staticmethod
    def check_verify_email_token(token):
        """验证token并获取user"""
        serializer = TJWSSerializer(settings.SECRET_KEY, expires_in=constants.VERIFY_EMAIL_TOKEN_EXPIRES)
        try:
            data = serializer.loads(token)
        except BadData:
            return None
        else:
            # data不是字典吗,为什么不能用x = data["x"]的方式获取值呢?
            # W:因为解密后的字典格式为:OrderDict[("name":"sss"),("sss":"ss")]
            email = data.get("email")
            user_id = data.get("user_id")
            try:
                user = User.objects.get(id=user_id, email=email)
            except User.DoesNotExist:
                return None
            else:
                return user


class Address(BaseModel):
    """
    用户地址
    """
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='addresses', verbose_name='用户')
    title = models.CharField(max_length=20, verbose_name='地址名称')
    receiver = models.CharField(max_length=20, verbose_name='收货人')
    province = models.ForeignKey('areas.Area', on_delete=models.PROTECT, related_name='province_addresses',
                                 verbose_name='省')
    city = models.ForeignKey('areas.Area', on_delete=models.PROTECT, related_name='city_addresses', verbose_name='市')
    district = models.ForeignKey('areas.Area', on_delete=models.PROTECT, related_name='district_addresses',
                                 verbose_name='区')
    place = models.CharField(max_length=50, verbose_name='地址')
    mobile = models.CharField(max_length=11, verbose_name='手机')
    tel = models.CharField(max_length=20, null=True, blank=True, default='', verbose_name='固定电话')
    email = models.CharField(max_length=30, null=True, blank=True, default='', verbose_name='电子邮箱')
    is_deleted = models.BooleanField(default=False, verbose_name='逻辑删除')

    class Meta:
        db_table = "tb_address"
        verbose_name = "用户地址"
        verbose_name_plural = verbose_name
        ordering = ["-update_time"]
